﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace QbservableHubTests.Serialization
{
    public class ExpressionVisitorTrace : ExpressionVisitor, IEnumerable<object>
    {
        private readonly Queue<object> _queue = new Queue<object>();

        public override Expression Visit(Expression node)
        {
            if (node != null)
            {
                _queue.Enqueue("====  " + node.NodeType.ToString() + "  ====");
            }
            return base.Visit(node);
        }
        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.Value);
                _queue.Enqueue(node.Type.FullName);
            }
            return base.VisitConstant(node);
        }
        protected override Expression VisitBinary(BinaryExpression node)
        {
            if (node != null)
            {
                if (node.Conversion != null)
                {
                    _queue.Enqueue(node.Conversion.Name);
                    var conv = node.Conversion.Parameters.Select(v => string.Format("Name - {0}, Type - {1}", v.Name, v.Type));
                    _queue.Enqueue(string.Join("; ", conv));
                    _queue.Enqueue(node.Conversion.ReturnType.FullName);
                    _queue.Enqueue(node.Conversion.TailCall);
                    _queue.Enqueue(node.Conversion.Type.FullName);
                }
            }
            return base.VisitBinary(node);
        }
        protected override Expression VisitBlock(BlockExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitBlock(node);
        }
        protected override CatchBlock VisitCatchBlock(CatchBlock node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitCatchBlock(node);
        }
        protected override Expression VisitConditional(ConditionalExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitConditional(node);
        }
        protected override Expression VisitDebugInfo(DebugInfoExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitDebugInfo(node);
        }
        protected override Expression VisitDefault(DefaultExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitDefault(node);
        }
        protected override Expression VisitDynamic(DynamicExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitDynamic(node);
        }
        protected override ElementInit VisitElementInit(ElementInit node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitElementInit(node);
        }
        protected override Expression VisitExtension(Expression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitExtension(node);
        }
        protected override Expression VisitGoto(GotoExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitGoto(node);
        }
        protected override Expression VisitIndex(IndexExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitIndex(node);
        }
        protected override Expression VisitInvocation(InvocationExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitInvocation(node);
        }
        protected override Expression VisitLabel(LabelExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitLabel(node);
        }
        protected override LabelTarget VisitLabelTarget(LabelTarget node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitLabelTarget(node);
        }
        protected override Expression VisitLambda<T>(Expression<T> node)
        {
            if (node != null)
            {
                
                _queue.Enqueue(node.Name);

                var conv = node.Parameters.Select(v => string.Format("Name - {0}, Type - {1}", v.Name, v.Type));
                _queue.Enqueue(string.Join("; ", conv));
                _queue.Enqueue(node.ReturnType.FullName);
                _queue.Enqueue(node.TailCall);
                _queue.Enqueue(node.Type.FullName);
            }
            return base.VisitLambda<T>(node);
        }
        protected override Expression VisitListInit(ListInitExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitListInit(node);
        }
        protected override Expression VisitLoop(LoopExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitLoop(node);
        }
        protected override Expression VisitMember(MemberExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitMember(node);
        }
        protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitMemberAssignment(node);
        }
        protected override MemberBinding VisitMemberBinding(MemberBinding node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitMemberBinding(node);
        }
        protected override Expression VisitMemberInit(MemberInitExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitMemberInit(node);
        }
        protected override MemberListBinding VisitMemberListBinding(MemberListBinding node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitMemberListBinding(node);
        }
        protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitMemberMemberBinding(node);
        }
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node != null)
            {
                var conv = node.Arguments.Select(v => string.Format("Type - {0}",v.Type));
                _queue.Enqueue(string.Join("; ", conv));
                _queue.Enqueue(node.Method.Name);
                _queue.Enqueue(node.Object);
                _queue.Enqueue(node.Type.FullName);
            }
            return base.VisitMethodCall(node);
        }
        protected override Expression VisitNew(NewExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitNew(node);
        }
        protected override Expression VisitNewArray(NewArrayExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitNewArray(node);
        }
        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.Name);
                _queue.Enqueue(node.Type.FullName);
            }
            return base.VisitParameter(node);
        }
        protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitRuntimeVariables(node);
        }
        protected override Expression VisitSwitch(SwitchExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitSwitch(node);
        }
        protected override SwitchCase VisitSwitchCase(SwitchCase node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitSwitchCase(node);
        }
        protected override Expression VisitTry(TryExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitTry(node);
        }
        protected override Expression VisitTypeBinary(TypeBinaryExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.ToString());
            }
            return base.VisitTypeBinary(node);
        }
        protected override Expression VisitUnary(UnaryExpression node)
        {
            if (node != null)
            {
                _queue.Enqueue(node.IsLifted);
                _queue.Enqueue(node.IsLiftedToNull);

                if (node.Method != null)
                    _queue.Enqueue(node.Method.Name);
                _queue.Enqueue(node.Type.FullName);
            }
            return base.VisitUnary(node);
        }

        public IEnumerator<object> GetEnumerator()
        {
            return _queue.GetEnumerator(); ;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}
